home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 176-200 / 197 / stevie / misccmds.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  11KB  |  492 lines

  1. /*
  2.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  3.  *
  4.  * Code Contributions By : Tim Thompson           twitch!tjt
  5.  *                         Tony Andrews           onecom!wldrdg!tony 
  6.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  7.  */
  8.  
  9. #include "stevie.h"
  10.  
  11. extern int      did_ai;
  12.  
  13. /*
  14.  * OpenForward 
  15.  *
  16.  * Add a blank line below the current line. 
  17.  */
  18.  
  19. bool_t
  20. OpenForward(can_ai)
  21.     int             can_ai;
  22. {
  23.     LINE           *l;
  24.     LPtr           *next;
  25.     char           *s;        /* string to be moved to new line, if any */
  26.     int             newindex = 0;    /* index of the cursor on the new
  27.                      * line */
  28.  
  29.     /*
  30.      * If we're in insert mode, we need to move the remainder of the current
  31.      * line onto the new line. Otherwise the new line is left blank. 
  32.      */
  33.     if (State == INSERT)
  34.     s = &Curschar->linep->s[Curschar->index];
  35.     else
  36.     s = "";
  37.  
  38.     if ((next = nextline(Curschar)) == NULL)    /* open on last line */
  39.     next = Fileend;
  40.  
  41.     /*
  42.      * By asking for as much space as the prior line had we make sure that
  43.      * we'll have enough space for any auto-indenting. 
  44.      */
  45.     if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) {
  46.     emsg("out of memory");
  47.     beep();
  48.     sleep(2);
  49.     return (FALSE);
  50.     }
  51.     if (can_ai && P(P_AI)) {
  52.     char           *p;
  53.  
  54.     /*
  55.      * Copy prior line, and truncate after white space 
  56.      */
  57.     strcpy(l->s, Curschar->linep->s);
  58.  
  59.     for (p = l->s; *p == ' ' || *p == TAB; p++);
  60.     *p = NUL;
  61.     newindex = p - l->s;
  62.     AppendToInsbuff(l->s);
  63.     if (*s != NUL)
  64.         strcat(l->s, s);
  65.  
  66.     /*
  67.      * If we just did an auto-indent, then we didn't type anything on the
  68.      * prior line, and it should be truncated. 
  69.      */
  70.     if (did_ai)
  71.         Curschar->linep->s[0] = NUL;
  72.  
  73.     did_ai = TRUE;
  74.     } else if (*s != NUL) {
  75.     strcpy(l->s, s);    /* copy string to new line */
  76.     }
  77.     if (State == INSERT)    /* truncate current line at cursor */
  78.     *s = NUL;
  79.  
  80.     Curschar->linep->next = l;    /* link neighbors to new line */
  81.     next->linep->prev = l;
  82.  
  83.     l->prev = Curschar->linep;    /* link new line to neighbors */
  84.     l->next = next->linep;
  85.  
  86.     if (next == Fileend) {    /* new line at end */
  87.     l->num = Curschar->linep->num + LINEINC;
  88.     } else if ((l->prev->num) + 1 == l->next->num) {    /* no gap, renumber */
  89.     renum();
  90.     } else {            /* stick it in the middle */
  91.     long            lnum;
  92.  
  93.     lnum = (l->prev->num + l->next->num) / 2;
  94.     l->num = lnum;
  95.     }
  96.  
  97.     if (!RedrawingDisabled) {
  98.     /*
  99.      * Get the cursor to the start of the line, so that 'Cursrow' gets
  100.      * set to the right physical line number for the stuff that
  101.      * follows... 
  102.      */
  103.     Curschar->index = 0;
  104.     cursupdate();
  105.  
  106.     /*
  107.      * If we're doing an open on the last logical line, then go ahead and
  108.      * scroll the screen up. Otherwise, just insert a blank line at the
  109.      * right place. We use calls to plines() in case the cursor is
  110.      * resting on a long line. 
  111.      */
  112.     if (Cursrow + plines(Curschar) == (Rows - 1))
  113.         scrollup(1);
  114.     else
  115.         s_ins(Cursrow + plines(Curschar), 1, Rows, Columns);
  116.     }
  117.     *Curschar = *nextline(Curschar);    /* cursor moves down */
  118.     Curschar->index = newindex;
  119.  
  120.     if (!RedrawingDisabled) {
  121.     /* because Botchar is now invalid */
  122.     updateNextscreen(VALID_TO_CURSCHAR);
  123.     cursupdate();        /* update Cursrow before insert */
  124.     }
  125.     CHANGED;
  126.  
  127.     return (TRUE);
  128. }
  129.  
  130. /*
  131.  * OpenBackward 
  132.  *
  133.  * Add a blank line above the current line. 
  134.  */
  135.  
  136. bool_t
  137. OpenBackward(can_ai)
  138.     int             can_ai;
  139. {
  140.     LINE           *l;
  141.     LINE           *prev;
  142.     int             newindex = 0;    /* index of the cursor on the new
  143.                      * line */
  144.  
  145.     prev = Curschar->linep->prev;
  146.  
  147.     if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) {
  148.     emsg("out of memory");
  149.     beep();
  150.     sleep(2);
  151.     return (FALSE);
  152.     }
  153.     Curschar->linep->prev = l;    /* link neighbors to new line */
  154.     prev->next = l;
  155.  
  156.     l->next = Curschar->linep;    /* link new line to neighbors */
  157.     l->prev = prev;
  158.  
  159.     if (can_ai && P(P_AI)) {
  160.     char           *p;
  161.  
  162.     /*
  163.      * Copy current line, and truncate after white space 
  164.      */
  165.     strcpy(l->s, Curschar->linep->s);
  166.  
  167.     for (p = l->s; *p == ' ' || *p == TAB; p++);
  168.     *p = NUL;
  169.     newindex = p - l->s;
  170.     AppendToInsbuff(l->s);
  171.  
  172.     did_ai = TRUE;
  173.     }
  174.     Curschar->linep = Curschar->linep->prev;
  175.     Curschar->index = newindex;
  176.  
  177.     if (prev == Filetop->linep) {    /* new start of file */
  178.     Filemem->linep = l;
  179.     renum();
  180.     } else if ((l->prev->num) + 1 == l->next->num) {    /* no gap, renumber */
  181.     renum();
  182.     } else {            /* stick it in the middle */
  183.     long            lnum;
  184.  
  185.     lnum = (l->prev->num + l->next->num) / 2;
  186.     l->num = lnum;
  187.     }
  188.  
  189.     if (!RedrawingDisabled) {
  190.     if (LINEOF(Curschar) < LINEOF(Topchar)) {
  191.         Topchar->linep = Curschar->linep;
  192.         updateNextscreen(NOT_VALID);
  193.     } else {
  194.         updateNextscreen(VALID_TO_CURSCHAR);
  195.     }
  196.     cursupdate();        /* update Cursrow before insert */
  197.     if (Cursrow != 0)
  198.         s_ins(Cursrow, 1, Rows, Columns);    /* insert a physical line */
  199.     }
  200.     CHANGED;
  201.  
  202.     return (TRUE);
  203. }
  204.  
  205. int
  206. cntllines(pbegin, pend)
  207.     LPtr           *pbegin, *pend;
  208. {
  209.     register LINE  *lp;
  210.     register int    lnum = 1;
  211.  
  212.     for (lp = pbegin->linep; lp != pend->linep; lp = lp->next)
  213.     lnum++;
  214.  
  215.     return (lnum);
  216. }
  217.  
  218. /*
  219.  * plines(p) - return the number of physical screen lines taken by line 'p' 
  220.  */
  221. int
  222. plines(p)
  223.     LPtr           *p;
  224. {
  225.     register int    col = 0;
  226.     register char  *s;
  227.  
  228.     if (p == NULL) {
  229.     fprintf(stderr, "plines(p) : p == NULL ????");
  230.     return (0);
  231.     }
  232.     s = p->linep->s;
  233.  
  234.     if (*s == NUL)        /* empty line */
  235.     return 1;
  236.  
  237.     for (; *s != NUL; s++) {
  238.     if (*s == TAB && !P(P_LS))
  239.         col += P(P_TS) - (col % P(P_TS));
  240.     else
  241.         col += chars[(unsigned) (*s & 0xff)].ch_size;
  242.     }
  243.  
  244.     /*
  245.      * If list mode is on, then the '$' at the end of the line takes up one
  246.      * extra column. 
  247.      */
  248.     if (P(P_LS))
  249.     col += 1;
  250.  
  251.     /*
  252.      * If 'number' mode is on, add another 8. 
  253.      */
  254.     if (P(P_NU))
  255.     col += 8;
  256.  
  257.     return ((col + (Columns - 1)) / Columns);
  258. }
  259.  
  260. void
  261. fileinfo()
  262. {
  263.     long            l1, l2;
  264.     char            buf[MAX_COLUMNS + 1];
  265.  
  266.     if (bufempty()) {
  267.     msg("Buffer Empty");
  268.     return;
  269.     }
  270.     l1 = cntllines(Filemem, Curschar);
  271.     l2 = cntllines(Filemem, Fileend) - 1;
  272.     sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --",
  273.         (Filename != NULL) ? Filename : "No File",
  274.         Changed ? " [Modified]" : "",
  275.         l1, l2, (l1 * 100) / l2);
  276.     msg(buf);
  277. }
  278.  
  279. /*
  280.  * gotoline(n) - return a pointer to line 'n' 
  281.  *
  282.  * Returns a pointer to the last line of the file if n is zero, or beyond the
  283.  * end of the file. 
  284.  */
  285. LPtr           *
  286. gotoline(n)
  287.     int             n;
  288. {
  289.     static LPtr     l;
  290.  
  291.     l.index = 0;
  292.  
  293.     if (n == 0)
  294.     l = *prevline(Fileend);
  295.     else {
  296.     LPtr           *p;
  297.  
  298.     for (l = *Filemem; --n > 0; l = *p)
  299.         if ((p = nextline(&l)) == NULL)
  300.         break;
  301.     }
  302.     return &l;
  303. }
  304.  
  305. void
  306. inschar(c)
  307.     char            c;
  308. {
  309.     register char  *p;
  310.     register char  *pend;
  311.  
  312.     /* make room for the new char. */
  313.     if (!canincrease(1))
  314.     return;
  315.  
  316.     p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1];
  317.     pend = &Curschar->linep->s[Curschar->index];
  318.  
  319.     for (; p > pend; p--)
  320.     *p = *(p - 1);
  321.  
  322.     *p = c;
  323.  
  324.     if (RedrawingDisabled) {
  325.     Curschar->index++;
  326.     return;
  327.     }
  328.     /*
  329.      * If we're in insert mode and showmatch mode is set, then check for
  330.      * right parens and braces. If there isn't a match, then beep. If there
  331.      * is a match AND it's on the screen, then flash to it briefly. If it
  332.      * isn't on the screen, don't do anything. 
  333.      */
  334.     if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) {
  335.     LPtr           *lpos, csave;
  336.  
  337.     if ((lpos = showmatch()) == NULL)    /* no match, so beep */
  338.         beep();
  339.     else if (LINEOF(lpos) >= LINEOF(Topchar)) {
  340.         updateNextscreen(VALID_TO_CURSCHAR);    /* show the new char
  341.                              * first */
  342.         updateRealscreen();
  343.         csave = *Curschar;
  344.         *Curschar = *lpos;    /* move to matching char */
  345.         cursupdate();
  346.         windgoto(Cursrow, Curscol);
  347.         delay();        /* brief pause */
  348.         *Curschar = csave;    /* restore cursor position */
  349.         cursupdate();
  350.     }
  351.     }
  352.     inc(Curschar);
  353.  
  354.     CHANGED;
  355. }
  356.  
  357. void
  358. insstr(s)
  359.     register char  *s;
  360. {
  361.     register char  *p;
  362.     register char  *pend;
  363.     register int    n = strlen(s);
  364.  
  365.     /* Move everything in the file over to make */
  366.     /* room for the new string. */
  367.     if (!canincrease(n))
  368.     return;
  369.  
  370.     p = &Curschar->linep->s[strlen(Curschar->linep->s) + n];
  371.     pend = &Curschar->linep->s[Curschar->index];
  372.  
  373.     for (; p > pend; p--)
  374.     *p = *(p - n);
  375.  
  376.     for (; n > 0; n--) {
  377.     *p++ = *s++;
  378.     Curschar->index++;
  379.     }
  380.     CHANGED;
  381. }
  382.  
  383. bool_t
  384. delchar(fixpos, undo)
  385.     bool_t          fixpos;    /* if TRUE fix the cursor position when done */
  386.     bool_t          undo;    /* if TRUE put char deleted into Undo buffer */
  387. {
  388.     int             i;
  389.  
  390.     /* Check for degenerate case; there's nothing in the file. */
  391.     if (bufempty())
  392.     return FALSE;
  393.  
  394.     if (lineempty(Curschar))    /* can't do anything */
  395.     return FALSE;
  396.  
  397.     if (undo)
  398.     AppendToUndobuff(mkstr(gchar(Curschar)));
  399.  
  400.     /* Delete the char. at Curschar by shifting everything in the line down. */
  401.     for (i = Curschar->index + 1; i < Curschar->linep->size; i++)
  402.     Curschar->linep->s[i - 1] = Curschar->linep->s[i];
  403.  
  404.     /*
  405.      * If we just took off the last character of a non-blank line, we don't
  406.      * want to end up positioned at the newline. 
  407.      */
  408.     if (fixpos) {
  409.     if (gchar(Curschar) == NUL && Curschar->index > 0 && State != INSERT)
  410.         Curschar->index--;
  411.     }
  412.     CHANGED;
  413.     return TRUE;
  414. }
  415.  
  416. void
  417. delline(nlines, can_update)
  418.     int             nlines;
  419.     bool_t          can_update;
  420. {
  421.     register LINE  *p;
  422.     register LINE  *q;
  423.     int             doscreen;    /* if true, update the screen */
  424.     int             num_plines = 0;
  425.  
  426.     doscreen = can_update;
  427.     /*
  428.      * There's no point in keeping the screen updated if we're deleting more
  429.      * than a screen's worth of lines. 
  430.      */
  431.     if (nlines > (Rows - 1) && can_update) {
  432.     doscreen = FALSE;
  433.     /* flaky way to clear rest of screen */
  434.     s_del(Cursrow, Rows - 1, Rows, Columns);
  435.     }
  436.     while (nlines-- > 0) {
  437.  
  438.     if (bufempty())        /* nothing to delete */
  439.         break;
  440.  
  441.     if (buf1line()) {    /* just clear the line */
  442.         Curschar->linep->s[0] = NUL;
  443.         Curschar->index = 0;
  444.         break;
  445.     }
  446.     p = Curschar->linep->prev;
  447.     q = Curschar->linep->next;
  448.  
  449.     if (p == Filetop->linep) {    /* first line of file so... */
  450.         Filemem->linep = q;    /* adjust start of file */
  451.         Topchar->linep = q;    /* and screen */
  452.     }
  453.     p->next = q;
  454.     q->prev = p;
  455.  
  456.     clrmark(Curschar->linep);    /* clear marks for the line */
  457.  
  458.     /*
  459.      * Set up to delete the correct number of physical lines on the
  460.      * screen 
  461.      */
  462.     if (doscreen)
  463.         num_plines += plines(Curschar);
  464.  
  465.     /*
  466.      * If deleting the top line on the screen, adjust Topchar 
  467.      */
  468.     if (Topchar->linep == Curschar->linep)
  469.         Topchar->linep = q;
  470.  
  471.     free(Curschar->linep->s);
  472.     free((char *) (Curschar->linep));
  473.  
  474.     Curschar->linep = q;
  475.     Curschar->index = 0;    /* is this right? */
  476.  
  477.     CHANGED;
  478.  
  479.     /* If we delete the last line in the file, back up */
  480.     if (Curschar->linep == Fileend->linep) {
  481.         Curschar->linep = Curschar->linep->prev;
  482.         /* and don't try to delete any more lines */
  483.         break;
  484.     }
  485.     }
  486.     /*
  487.      * Delete the correct number of physical lines on the screen 
  488.      */
  489.     if (doscreen && num_plines > 0)
  490.     s_del(Cursrow, num_plines, Rows, Columns);
  491. }
  492.